ex6_1

形参出现在函数定义的部分，形参列表可以包含0个、1个或多个形参，多个形参之间用逗号分隔。形参规定了一个函数所接受数据的类型和数量；
实参是形参的初始值，出现在函数调用的地方，实参和形参的数量相等，实参和形参在初始化的过程中是一一对应的，实参的类型必须与对应的形参类型匹配。

ex6_2

(a)是错误的，因为函数体返回的结果是string类型的，而函数的返回值类型是int型的，二者不一致切不能自动转换，应该进行如下的修改:
         string f()
         {
            string s; 
            //...
            return s;
         }
(b)是错误的:f2没有说明是什么类型的(即函数缺少返回值类型)应进行如下修改:
           void f2(int i){/*...*/}
(c)是错误的:1.C++规定任意两个形参不能同名，2.函数左侧的花括号丢了。应进行如下修改:
            int calc(int v1,int v2){/*...*/}
(d)是错误的，形参缺少花括号，应进行如下的修改:
            double square (double x)
            {
              return x*x;
            }
            
ex6_6

形参和函数体内部定义的变量统称为局部变量，局部变量仅在函数的作用域内可见；
函数体内的局部变量又分为普通局部变量和静态局部变量；

局部变量：形参和函数体内部定义的变量统称为局部变量（注意其作用域）
局部静态对象：直到程序的结束才被销毁的对象，不受块的约束
            
ex6_12

与使用指针相比，使用引用交换变量的内容从形式上看更简单一些，并且无需额声明指针变量，也避免了拷贝指针的值。

ex6_13

void f(T)的形参采用的是传值调用的方式，即实参的值被拷贝给形参，形参和实参是两个相互独立的对象，在函数f内部对形参所做的任何改动都不会影响到实参的值；
void f(T&)的形参采用的是传引用调用的方式，即形参是对应的实参的别名，形参绑定到初始化它的对象，如果我们改变了形参的值，也就是改变了实参的值。

ex6_16

该函数的局限性在于将s定义为普通的引用，正如前面书中说道：使用引用而非常量引用会极大地限制函数所能接受的实参类型，而且如果其他函数将它们的形参定义成了
常量引用，那么普通引用版本的函数无法在此类函数中继续引用，应该进行如下修改：
             bool is_empty(const string& s){return s.empty();}

ex6_18

(a)的函数声明是：
bool compare(const matrix&,const matrix&)
(b)的函数声明是：
vactor<int>::iterator change_val()(int,vactor<int>::iterator)  //因为从给定的名字可以看出该迭代器需要可读可写，所以选用的迭代器类型是iterator

ex6_19

(a)是非法的：因为double calc(double)只包含一个double类型，而(a)中调用了两个double类型，因此说（a）是非法的；
(b)是合法的：因为int count(const string&, char)包含了一个常量字符串和一个普通字符类型，(b)中，用双引号“”引用的是字符串类型，用单引号''引用的是字符类型，即“abcda”是字符串，‘a’是字符，符合int count函数的规则，因此说（b）是合法的
(c)是合法的：因为虽然double calc(double)要求函数中的参数是一个double类型的数据，66是一个int类型的数据，但int型的数据可以转换成double类型的数据，所以（c）是合法的
(d)是合法的，因为vec.begin()和vec.end()的类型都是形参所需的vector<int>::iterator,第三个实参3.8可以自动转换为形参所需的int类型


ex6_20

如果不需要修改形参的内容，最好应该将形参设为常量引用类型；如果需要修改形参的内容，就把形参设置为普通引用类型
如果形参应该是常量引用，而我们将其设定为普通引用，那么会出现两个问题：
  1.容易给使用者造成误导，即程序允许修改实参的内容；
  2.极大地限制了该函数所能接受的实参类型，无法把const对象、字面值常量或者需要类型转换的对象传递给普通的引用类型

ex6_21

该函数定义了一个整形常量的数组，由“如果我们传给print函数的是一个数组，则实参自动地转换成指向数组首元素的指针”，可知本题中print函数的形参等价于一个常量整形指针const int*
另一方面根据数据的性质可知不能够拷贝数组，所以本段代码的错误在与用值传递的方式使用了数组的参数 应该进行如下的修改
   void print(const int (&ia)[10])
   {
      for(size_t i=0;i!=10;++i)
        cout<<ia[i]<<endl;
   }

ex6_24

根据数组的性质可知不能拷贝数组，所以不能用值传递的方式使用数组参数，这段代码犯的错误就是用值传递的方式使用了数组的参数，应该进行如下修改：
        void print(const int (&ia)[10])
        {
         for(size_t i=0;i!=10;++i)
         cout<<ia[i]<<endl;
        }

ex6_28

在包含Errcode的版本中，循环elem的初始值是initializer<string>,所以说elem的类型是const string类型的，使用引用的原因在189页：避免拷贝较长的字符串
使用常量的原因是因为只需要读取字符串，并不需要修改它，所以使用常量

ex6_29

在范围for语句中使用initializer_list对象不需要将循环控制变量声明为引用类型，因为initializer_list的元素永远是常量值，无法修改，又因为只有修改元素的时候才应该将循环控制变量声明称引用类型，因此说在范围for语句中使用initializer_list对象不需要讲循环控制变量声明为引用类型

ex6_30

使用vs2017对这段函数进行编译，编译器直接报错，并没有显示错误原因，但是真正的错误原因在for循环内的return语句是错误的，该return语句没有返回值，第二个错误是for循环之后没有提供return语句

ex6_31

如果返回的是局部对象的引用，那么该引用是无效的；
如果返回类型是常量引用，那么不能给调用的函数赋值，因此说如果需要调用的函数赋值，即返回的对象要被修改，此时返回类型是常量引用就是无效的

ex6_32

这段程序是合法的，get函数接受一个整形指针，该指针实际指向一个整形数组的首元素，另外还接受一个整数表示数组中某个元素的索引值。他的返回类型是整形引用，
引用的对象时array数组中的某个元素。当get函数执行完毕后，调用者得到实参数组array中索引为index的数组元素的引用
   在main函数中，首先创建一个包含10个参数的整形数组，然后进入循环，每次循环使用get函数得到数组ia中第i个元素的引用，将该引用赋值为i，当循环结束时，ia的元素依次被赋值为0~9

ex6_34

若停止条件修改为if(val!=0),那么当val为负数时，该函数永远无法停止

ex6_35

后置递减运算符用的是减去之前的那个值的副本，因此val--就会一直循环，达不到减一的目的


ex6_36
由题意可知应该使用返回数组引用的那个函数：
    string(&func () )[10]
其中func()表示调用func函数无需任何实参，(&func())表示函数的返回结果是一个引用，(&func () )[10]表示引用的对象是一个维度为10的数组，string(&func () )[10]表示数组的元素是string类型

ex6_37

使用类型别名的引用声明为： 
   typedef string arrT[10];
   &arrT func( );
使用尾置返回类型的引用声明为：
    auto func(string i) -> string(&)[10]
使用decltype的引用声明为:
     string str[10];
     decltype(str)&func( )

ex6_38

修改后的函数为：
         int odd[]={1,3,5,7,9};
         int even[]={0,2,4,6,8};
         decltype(odd) &arrPtr(int i)
         {
                  return (i%2)?odd:even;
         }

ex6_39

(a)第二个声明是非法的，它的含义和第一个声明是一样的，因为一个拥有顶层const的形参无法和另一个没有顶层const的形参区别开来，又因为重载函数规定：不允许两个函数除了返回类型之外其他所有的要素都相同，本题中第二个重载函数和第一个函数完全相同，所以(a)的第二个声明是非法的；

(b)的第二个声明是非法的：它的意图是通过返回类型的区别区分两个同名的函数，但是正如上面所说的那样，C++规定，重载函数必须在形参数量或者是形参类型上有所区别，如果两个同名函数的形参数量和类型都一样，那么即使返回类型不同也不行；

(c)的连那个函数是重载的关系，它们的形参类型是不同的

ex6_40

(a)是正确的；
(b)是错误的，因为一旦函数的某个形参被赋予了默认值，它后面所有的参数都必须有默认值；(b)中ht已经被赋予为了默认值，所以后面的wd、bckrnd都应该被赋予默认值，所以(b)是错误的

ex6_41

(a)是非法的：根据函数可以知道，该函数有2个默认实参，但是总共有3个形参，其中第一个形参未定义默认值，所以如果想要调用该函数，至少提供一个参数
(b)是合法的，因为这个调用提供了两个实参，第一个实参对应ht，第二个实参对应wd，第三个实参采用默认实参
(c)从语法上来说是合法的，但是从语义上来说与设想的不一样，原意是希望ht被赋予成14，wd用默认实参，bckgrnd用"*";
    但是实际上wd会被赋予*号

ex6_43

(a)函数中有关键字inline，可以证明(a)函数是一个内联函数，因为内联函数应该放在头文件中，所以要把（a）放在头文件中
(b)是一个函数声明，声明最好放在头文件中，所以综上，（a）、（b）都应该放在头文件中

ex6_44

将该函数改写为内联函数有：
 inline bool isShorter(const string &s1,const string &s2)
 {
         return s1.size()<s2.size();
 }
 
 ex6_45
 
 我之前在练习中编写的那些函数应该是内联函数，为什么呢？因为这些函数都满足了内联函数的如下要求：规模较小、流程直接、频繁调用
 如果想要把这些函数改写成内联函数，只需要在函数之前加上关键字“inline”即可


ex6_46

isShorter函数不能定义成constexpr函数，因为constexpr应该满足如下条件：1.函数的返回类型和所有的形参类型都必须是字面值类型（算术类型、引用、指针）2.有且只有一条return语句
isShorter函数虽然只有一条return语句，但是它的形参是string类型的，不是字面值类型的，所以不行

ex6_48

while循环的含义是当用户输入一个字符串直到这个字符串是sought时为止
这段循环对assert的使用是不合理的，因为当用户输入字符串s时，assert中的expr总是有数据（不为0），所以assert什么也不做
应进行如下修改：
assert(s==sought)

ex6_49

候选函数：函数匹配的第一步是选定本次调用的重载函数集，集合中的函数被称为候选函数;
可行函数：根据实参情况，从候选函数中挑选出能被这实参调用的函数，此次选出的函数被称为可行函数。

ex6_50
（a）根据函数匹配的步骤：1.排除f（）和f（int）；2.f（double，int）满足第一个实参，f（int，int）满足第二个实参，因此编译器会因为这个调用具有二义性而拒绝其请求；
（b）匹配f（int）
（c）匹配f（int，int）
（d）匹配f（double，double）

ex6_52

对于(a)调用来说，被调用的函数中的类型是int型的，而manip中的实参类型是字符型的，所以通过类型提升实现了匹配；
对于(b)调用来说，被调用的函数中的类型是int型的，而manip中的实参类型都是double类型的，所以通过算术类型转换实现了匹配

ex6_53

(a)是合法的，两个函数的区别在于它们的引用类型的形参是否引用了常量，属于底层const，可以把这两个函数区分开来
(b)是合法的，两个函数的区别在于它们的指针类型的形参是否引用了常量，属于底层const，可以把这两个函数区分开来
(c)是非法的，两个函数的区别在于它们的指针类型的形参本身是否是常量，因为第二条声明中的指针本身就是一个常量，所以是一个顶层const根据函数匹配的规则，向是实参中添加或删除顶层const都是精准匹配的情况，所以（c）中的两个函数无法区分开，因此是非法的

ex6_54

根据题意首先声明一个含有2个int形参且返回int类型的函数声明：
     int f(int ,int)
再声明一个vector对象，令其元素是指向该函数的指针：
         vector<decltype(f) *> v
 
